package com.olive.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PKCS7Padding;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;

public class AESUtil {
	/**
	 * 加密方式
	 */
	public static final String KEY_ALGORITHM = "AES";
	
	/**
	 * 安全随机签名算法
	 */
	public static final String SECURE_ALGORITHM = "SHA1PRNG";
	
	/**
	 * 加密算法
	 */
	public static final String SECRYPT_ALGORITHM = "AES/ECB/PKCS5Padding";
	
	private String privateKey = null;

	private String DEFAULT_ENCODING = "utf-8";

	/**
	 * 报文加密
	 * 
	 * @param randomKey
	 *            随机密钥
	 * @param plainData
	 *            上�?�报�?
	 * @return 报文密文
	 * @throws Exception
	 */
	public static String encrypt(String plainData, String randomKey) throws Exception {
		KeyGenerator aesGen = KeyGenerator.getInstance(KEY_ALGORITHM);
		SecureRandom secureRandom = SecureRandom.getInstance(SECURE_ALGORITHM);
		secureRandom.setSeed(randomKey.getBytes());
		aesGen.init(128, secureRandom);

		SecretKey secretKey = aesGen.generateKey();
		SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
		Security.addProvider(BouncyCastleProviderBuilder.build());
		Cipher aesCipher = Cipher.getInstance(SECRYPT_ALGORITHM, "BC");
		aesCipher.init(Cipher.ENCRYPT_MODE, keySpec);
		byte[] aesData = aesCipher.doFinal(plainData.getBytes("utf-8"));
		return Base64.encodeBase64String(aesData);
	}
	
	/**
	 * 报文解密
	 * 
	 * @param aesBase64
	 * @param randomKey
	 * @return
	 * @throws Exception
	 */
	public static String decrypt(String aesBase64, String randomKey) throws Exception {
		byte[] aesData = Base64.decodeBase64(aesBase64);
		KeyGenerator aesGen = KeyGenerator.getInstance(KEY_ALGORITHM);
		SecureRandom secureRandom = SecureRandom.getInstance(SECURE_ALGORITHM);
		secureRandom.setSeed(randomKey.getBytes());
		aesGen.init(128, secureRandom);
		SecretKey secretKey = aesGen.generateKey();
		SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
		Security.addProvider(BouncyCastleProviderBuilder.build());
		Cipher aesCipher = Cipher.getInstance(SECRYPT_ALGORITHM, "BC");
		aesCipher.init(Cipher.DECRYPT_MODE, keySpec);
		byte[] plain = aesCipher.doFinal(aesData);
		String plainData = new String(plain, Charset.forName("utf-8"));
		return plainData;
	}

	public static String encryptWithBC(String data, String key) throws Exception {
		ByteBuffer buffer = ByteBuffer.allocate(32);
		buffer.put(key.getBytes());
		KeyParameter kp = new KeyParameter(buffer.array());
		byte[] bytes = data.getBytes("UTF8");

		CBCBlockCipher aes = new CBCBlockCipher(new AESEngine());
		PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(aes, new PKCS7Padding());
		cipher.init(true, kp);

		byte[] output = new byte[cipher.getOutputSize(bytes.length)];
		int len = cipher.processBytes(bytes, 0, bytes.length, output, 0);
		cipher.doFinal(output, len);

		return Base64.encodeBase64String(output);
	}

	/**
	 * https://segmentfault.com/a/1190000016251926
	 * 
	 * @param data
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static String decryptWithBC(String data, String key) throws Exception {
		ByteBuffer buffer = ByteBuffer.allocate(32);
		buffer.put(key.getBytes());
		KeyParameter kp = new KeyParameter(buffer.array());

		byte[] bytes = Base64.decodeBase64(data);

		CBCBlockCipher aes = new CBCBlockCipher(new AESEngine());
		PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(aes, new PKCS7Padding());
		cipher.init(false, kp);

		byte[] output = new byte[cipher.getOutputSize(bytes.length)];
		int len = cipher.processBytes(bytes, 0, bytes.length, output, 0);
		int len2 = cipher.doFinal(output, len);
		byte rawData[] = new byte[len + len2];
		System.arraycopy(output, 0, rawData, 0, rawData.length);
		String plainData = new String(rawData, Charset.forName("utf-8"));
		return plainData;
	}

	/**
	 * 生成随机密钥，一次一�?
	 * 
	 * @return
	 */
	public static String getRandomKey() {
		SecureRandom random = new SecureRandom();
		long randomKey = random.nextLong();
		return String.valueOf(randomKey);
	}

	/**
	 * 加密与解�?
	 * 
	 * @param encrypt
	 *            true 加密�? false 解密
	 * @param inputBytes
	 * @return
	 * @throws Exception
	 */
	public byte[] transform(boolean encrypt, byte[] inputBytes) throws Exception {
		MessageDigest messageDigest = MessageDigest.getInstance("MD5");
		messageDigest.reset();
		messageDigest.update(privateKey.getBytes(DEFAULT_ENCODING));
		byte[] key = messageDigest.digest();

		BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
		cipher.init(encrypt, new KeyParameter(key));

		ByteArrayInputStream input = new ByteArrayInputStream(inputBytes);
		ByteArrayOutputStream output = new ByteArrayOutputStream();

		int inputLen;
		int outputLen;

		byte[] inputBuffer = new byte[1024];
		byte[] outputBuffer = new byte[cipher.getOutputSize(inputBuffer.length)];

		while ((inputLen = input.read(inputBuffer)) > -1) {
			outputLen = cipher.processBytes(inputBuffer, 0, inputLen, outputBuffer, 0);
			if (outputLen > 0) {
				output.write(outputBuffer, 0, outputLen);
			}
		}

		outputLen = cipher.doFinal(outputBuffer, 0);
		if (outputLen > 0) {
			output.write(outputBuffer, 0, outputLen);
		}

		return output.toByteArray();
	}

	/**
	 * http://www.mamicode.com/info-detail-2555584.html
	 * 
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		String aesRandomKey = "121231231231231231233";
		System.out.println(aesRandomKey);
		String e = AlgorithmUtil.encryptWithAES("adfafafadfafafadfafaadfafafadfafafadfafa11adfafafadfafafadfafaadfafafadfafafadfafa111111111111fadfafafadfafaf111111111111fadfafafadfafafadfafafadfafafadfafaadfafafadfafafadfafa111111111111fadfafafadfafaf111111111111fadfafafadfafafadfafafadfafafadfafaadfafafadfafafadfafa11adfafafadfafafadfafaadfafafadfafafadfafa111111111111fadfafafadfafaf111111111111fadfafafadfafafadfafafadfafafadfafaadfafafadfafafadfafa111111111111fadfafafadfafaf111111111111fadfafafadfafaf1111111111fadfafafadfafaf111111111111fadfafafadfafafadfafafadfafafadfafaadfafafadfafafadfafa11adfafafadfafafadfafaadfafafadfafafadfafa111111111111fadfafafadfafaf111111111111fadfafafadfafafadfafafadfafafadfafaadfafafadfafafadfafa111111111111fadfafafadfafaf111111111111fadfafafadfafaf1111111111fadfafafadfafaf111111111111fadfafafadfafafadfafafadfafafadfafaadfafafadfafafadfafa11adfafafadfafafadfafaadfafafadfafafadfafa111111111111fadfafafadfafaf111111111111fadfafafadfafafadfafafadfafafadfafaadfafafadfafafadfafa111111111111fadfafafadfafaf111111111111fadfafafadfafaf1111111111fadfafafadfafaf111111111111fadfafafadfafaf1111111111fadfafafadfafaf111111111111fadfafafadfafaf", aesRandomKey);
		System.out.println(e);
		System.out.println(AlgorithmUtil.decryptWithAES("q9kz7SXBaf+oxM14VZRvLWLbOz/QbYJeitGLuShbZ3D6IGn+0YeaVLtuJ12kN3s7xQRzB82HNC9O0RiR/rs+bqv/WZdUfRA4DLmRckTmDhJYUNQSp/evbwXkPJgwiNLsg4kQj9DFLu2evajZV6zN0kLiCm0bxqfp5UbNRNHuJpQPBDJiRhq04/kzNm/GMpw4v2cly2+yYGeg2vVPXwftuHkOPeFysoqrbbm4bRNbyB1w0ZqxwZKJa6RuSVj8oWg/7UH77e+jmdruTrcFT8z9JIX3A+fHZr9X6kiLBR0ez2RbKM8QM1tz5hLaXwAD4x5pYjOZUfRLfAWKT6vO19BwIkRFqccCWr5ao98ubH2IprDaAHzxDLfBYMYOUWVEZYc2uVV2Vn5rJIJLMvr+bWH04hk0pxsuhAR3g3y4m/yYDmw50M6lSM3jQf5jM4NKHQzWjSZr6phtQFscunkf8QPNcajjv3wA+OdCJAK8xQoGWYgc7yzk17W10FE+R/+GF0sMFAQeVsM0piUfe8PBT4ysBVeq9/qioz359++TYXe9gpphyqXNhlFbwbv0SnmHub9JemPfeyPamEsteIdkWASvAgvkRrxQreNnoPE4jw7R/ySkOm0h50A5hG5AnQhcQK1IItNIblwaNH1/TQf+khY3n2TRqZf0Nqf7NelQWkcE3ntzyUBa/BfsxFRijZkEZbb+2XZwIRuhQLpzFG9+LTiOyvfqgOn8Qj6h0RelNpow4LGfrsWPLND/EAjuHXf6SLCw6PQWaf8mqTZqpCLdxf6IfO9apcz0xMwqVX98VwWLSzMr2RLxiI9GYAwRhUb42TrJyLHbXL4/H1kO52lV4WZd6fhtx2Bdu7kRKRR/QpvyLdnwbuumsGO/OVFM+3RA0UrknwX+7arpEXksQRPRl1tTXoHmvL1v3RTzGff31DfQq3RjKnOS7HaczZAoBnf5LB9z3foTbO56nsakWkmh20GaaLqYa3T+iadNSIunjssPfSKZy0EO8lhNMaKZM+DwmOPDTx3H/YCMZfOCcmyXdH96ADsDpP+aLdDPDrn6L0c72Y2C3IdHf3079QSuxjAJUnV1J6zkRP2KVxqbeCYD5YlJai+LLtDbHVaQIX83VkSsaSr1gj8oZlRwGBlqBudna6IXErO2QZIy7F1LV/bMfp9j7HJZ5vsHjjaPjhHJK1BvQJoPreAyKe2w+/XNSwpAFA2X7giPGfZitJyykGs3XKNAWAd5X6FMNEUlzgz+06BPbxFNkZApjSdGLhM91VVpkRxWdcwPbds1jTXF/yM/MMwE3WSUeeE20ktmoaXJf2OeCB+n4/OiAbcOy5mn7kystq0Sz5gDWRKz1JHJjpfpOo8obd2xLDM30yvGsOBMY1IjOb1pDj3C/1CjXBwxJcRZlrBY/Qf2e9EX5o8+H6kZQMkf6lhDriLUDu2INUBxmu7E89VHz9J6Gyaxd/In7CRhg+Zx71CaqR2WHtvWJ44BWZuWdJZMJm2IS6BanOhQ4zvv5FU=", aesRandomKey));
	}
}